package com.zxy.supplier_system.server.xinyuan.configuration

import com.zxy.supplier_system.server.utils.LoggerDelegate
import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.context.properties.bind.ConstructorBinding
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpHeaders
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.User
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UserDetailsService
import org.springframework.security.provisioning.InMemoryUserDetailsManager
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.web.filter.OncePerRequestFilter
import java.util.*

const val AUTHORIZATION_HEADER_BASIC_PREFIX = "Basic"

@Configuration
@EnableConfigurationProperties(AdminUsernameProperties::class)
class AdminSecurityConfiguration {

    @Bean
    fun personDetailService(adminUsernameProperties: AdminUsernameProperties): UserDetailsService {
        val user = User.withUsername(adminUsernameProperties.username)
            .password(adminUsernameProperties.password)
            .build()

        return InMemoryUserDetailsManager(user)
    }

}

@ConfigurationProperties(prefix = "xinyuan.admin")
class AdminUsernameProperties @ConstructorBinding constructor(
    val username: String,
    val password: String
)

class BasicTokenAuthorizationFilter(
    private val validUsername: String,
    private val validPassword: String
) : OncePerRequestFilter() {

    companion object {
        private val log by LoggerDelegate()
    }

    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val authorizationHeader = request.getHeader(HttpHeaders.AUTHORIZATION)
        if (authorizationHeader != null && authorizationHeader.startsWith(AUTHORIZATION_HEADER_BASIC_PREFIX)) {
            try {
                log.debug("校验BasicToken，注入AuthenticationToken到上下文中，url: {}", request.requestURL)

                val base64Credentials = authorizationHeader.substring(AUTHORIZATION_HEADER_BASIC_PREFIX.length + 1)
                val decodedCredentials = String(Base64.getDecoder().decode(base64Credentials))
                val credentials = decodedCredentials.split(":", limit = 2)
                if (credentials.size == 2) {
                    val username = credentials[0]
                    val password = credentials[1]

                    // 验证凭证
                    if (username == validUsername && password == validPassword) {
                        // 创建认证对象
                        val authentication = createAuthentication(username, request)

                        // 注入安全上下文
                        SecurityContextHolder.getContext().authentication = authentication
                    }
                }

            } catch (e: Exception) {
                logger.error("Basic token decoding failed", e)
            }
        }
        filterChain.doFilter(request,response)

    }

    private fun createAuthentication(
        username: String,
        request: HttpServletRequest
    ): UsernamePasswordAuthenticationToken {
        // 创建 UserDetails 对象
        val userDetails = createUserDetails(username)

        // 创建认证令牌
        val authentication = UsernamePasswordAuthenticationToken(
            userDetails,
            null,
            userDetails.authorities
        )

        // 设置请求详情
        authentication.details = WebAuthenticationDetailsSource().buildDetails(request)

        return authentication
    }

    private fun createUserDetails(username: String): UserDetails {
        return object : UserDetails {
            override fun getAuthorities() = emptyList<GrantedAuthority>()
            override fun getPassword() = ""
            override fun getUsername() = username
            override fun isAccountNonExpired() = true
            override fun isAccountNonLocked() = true
            override fun isCredentialsNonExpired() = true
            override fun isEnabled() = true
        }
    }

}
